import { getToken } from '@/services/tokenInfo';
import type { UploadChangeParam, RcFile } from 'antd/lib/upload/interface';
import { message } from 'antd';
import type { SortOrder } from 'antd/lib/table/interface';
import omit from 'omit.js';
import moment from 'moment';
import type { RangePickerProps } from 'antd/es/date-picker/generatePicker';

// 默认头像图片
export const ArartaUrl =
  'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png';

// 加载失败显示图像占位符
export const ImgFallback =
  '';

export const PrefixUrl = '/api/admin';

// --------------------------------------------------------------
export const SexOptions = [
  {
    label: '保密',
    value: 0,
  },
  {
    label: '男',
    value: 1,
  },
  {
    label: '女',
    value: 2,
  },
];

// ---------------定义抽屉组件的全局量变DrawerForm-------------------------------
export const drawerProps = {
  forceRender: true,
  destroyOnClose: true,
  maskClosable: false,
};

// ---------------定义modal组件的全局量变DrawerForm-------------------------------
export const modalProps = {
  forceRender: true,
  destroyOnClose: true,
  maskClosable: false,
};

/**
 * 为了调用List页面的方法，让这个页面关闭。
 * 由于每个页面都需要这个函数，所以做成了公用函数
 * @param visibled 点击关闭按钮，确认按钮，等按钮后传递过来的数值
 */
export const onVisibleChangeHandle = (
  visibled: boolean,
  setVisible: (visible: boolean) => void,
) => {
  if (!visibled) {
    setVisible(false);
  }
};

// --------------------------图片上传函数-----------------------------------------------

export type UploadEndPros<T = any> = {
  fileName: string;
  success: boolean;
  response?: T;
};

/**
 * name : request中组件的名称，默认是file
 * actionUrl: 要调用的上传组件的Url，不需要填写前缀
 * setUploading：设置loading的函数
 * onUploadEnd：上传结束后，回调的函数
 */
export type UploadImgParaProps<T = any> = {
  name?: string;
  actionUrl: string;
  setUploading?: (loading: boolean) => void;
  onUploadEnd: (para: UploadEndPros<T>) => void;
};

/**
 * 得到上传文件的定义，在个人设置中的头像上传用到。
 * 如果将这堆方法都放在一个文件中，感觉不好理解。
 * 功能说明：
 *  1：传递一个token，因为后台的上传接口都需要权限认证
 *  2：当上传的过程中，可以显示loading
 *  3: 可以过滤文件类型
 *  4：可以将上传的状态，返回给前台。
 *  5：T 后台放回的数据结构
 * @param paras
 */
export function getSingleUploadImgProps<T = any>(paras: UploadImgParaProps<T>) {
  const { name = 'file', actionUrl, setUploading, onUploadEnd } = paras;

  const uploadProps = {
    name,
    action: `${PrefixUrl}${actionUrl}`,
    headers: {
      Authorization: getToken() as string,
    },
    beforeUpload: (file: RcFile) => {
      if (setUploading) {
        setUploading(true);
      }
      const isJpgOrPng: boolean = file.type === 'image/jpeg' || file.type === 'image/png';

      if (!isJpgOrPng) {
        if (setUploading) {
          setUploading(false);
        }
        message.error(`只能上传JPG/PNG文件：${file.name}`);
        onUploadEnd({ success: false, fileName: file.name });
      }

      const isLt2M = file.size / 1024 / 1024 < 2;
      if (!isLt2M) {
        if (setUploading) {
          setUploading(false);
        }
        message.error('上传文件必须小于2M');
        onUploadEnd({ success: false, fileName: file.name });
      }

      return isJpgOrPng && isLt2M;
    },
    showUploadList: false,
    onChange(info: UploadChangeParam) {
      if (info.file.status === 'done') {
        if (setUploading) {
          setUploading(false);
        }
        message.success(`${info.file.name} file uploaded successfully`);
        onUploadEnd({ success: true, fileName: info.file.name, response: info.file.response });
      } else if (info.file.status === 'error') {
        if (setUploading) {
          setUploading(false);
        }
        message.error(`${info.file.name} file upload failed.`);
        onUploadEnd({ success: false, fileName: info.file.name });
      }
    },
  };
  return uploadProps;
}

export const getUrlFileName = (url: string | undefined) => {
  if (!url) {
    return '';
  }
  const index = url.lastIndexOf('/');
  return url.substring(index + 1, url.length);
};

// 上传单个临时文件，例如设置模块中上传siteLogo
export function getBeforeUpload() {
  const beforeUpload = (file: RcFile) => {
    const isJpgOrPng: boolean = file.type === 'image/jpeg' || file.type === 'image/png';
    if (!isJpgOrPng) {
      message.error(`只能上传JPG/PNG文件：${file.name}`);
    }
    const isLt2M = file.size / 1024 / 1024 < 2;
    if (!isLt2M) {
      message.error('上传文件必须小于2M');
    }
    return isJpgOrPng && isLt2M;
  };
  return beforeUpload;
}

//  --------------------------公用函数-----------------------------------------------

/**
 * 将Id转换成一个name，多用在select checkbox table中使用
 * @param initValues 默认值，例如想添加一个全部，但是这个全部不在数据库中
 * @param originalValues  从数据中查询出来的数值
 * @param labelName  数据库中的label字段名
 * @param valueName  数据库中value的字段名
 *
 * 备注：如果遇到一个复杂的，那就自己写相关的函数吧。
 */
export function convertToOptions(
  initValues: any[],
  originalValues: any[],
  labelName: string,
  valueName: string,
) {
  let options: any[] = [];
  if (initValues) {
    options = initValues;
  }
  if (originalValues) {
    originalValues.forEach((item) => {
      options.push({
        label: item[labelName],
        value: item[valueName],
      });
    });
  }
  return options;
}

export function convertToValueEnum(originalValues: any[], labelName: string, valueName: string) {
  const options = {};
  if (originalValues) {
    originalValues.forEach((item) => {
      options[item[valueName]] = item[labelName];
    });
  }
  return options;
}

/**
 * 得到一个32位的随机字符串，用在设置密码时的初始密码。
 */
export function makeString(): string {
  let outString: string = '';
  const inOptions: string = 'abcdefghijklmnopqrstuvwxyz0123456789';
  for (let i = 0; i < 32; i += 1) {
    outString += inOptions.charAt(Math.floor(Math.random() * inOptions.length));
  }
  return outString;
}

/**
 * 在登录页面中，通过ID判断是新增，还是编辑。
 * @param id
 */
export function isAdd(id: string | number | undefined): boolean {
  if (!id || id === 0 || id < 0) return true;

  if (typeof id === 'string') {
    if (id.trim() === '' || id.trim() === '0') return true;
  }

  return false;
}

export declare type GetRegExpType =
  | 'cname'
  | 'mobilePhone'
  | 'telePhone'
  | 'email'
  | 'idCard'
  | 'qq'
  | 'name'
  | 'zip'
  | 'number';

/**
 * 返回常用的增则表达式
 * 参考了这个网址：https://blog.csdn.net/itbrand/article/details/109239620
 * @param regType
 */
export function getRegExp(regType: GetRegExpType): RegExp {
  const regExps = {
    // 2-4个中文字符正则
    cname: /^[\u4e00-\u9fa5]{2,4}$/,
    // 手机号码
    mobilePhone: /^(13[0-9]|14[01456879]|15[0-3,5-9]|16[2567]|17[0-8]|18[0-9]|19[0-3,5-9])\d{8}$/,
    // 座机号码
    telePhone: /^(0\d{2,3})-?(\d{7,8})$/,
    // 电子邮箱
    email: /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/,
    // 身份证号码:普通校验  如果要更加准确的，见参考网址
    idCard: /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/,
    // QQ号码
    qq: /^[1-9][0-9]\d{4,9}$/,
    // 注册账号
    name: /^[a-zA-Z][a-zA-Z0-9_]{4,15}$/,
    // 邮编
    zip: /^[a-zA-Z][a-zA-Z0-9_]{4,15}$/,
    // 匹配非负整数（正整数 + 0）
    number: /((^\+?[1-9][0-9]*)|(0))$/,
  };
  return regExps[regType];
}

function getASC(para: 'descend' | 'ascend' | null): string {
  if (para === null) {
    return 'ASC';
  }

  if (para === 'ascend') {
    return 'ASC';
  }

  if (para === 'descend') {
    return 'DESC';
  }
  return 'ASC';
}

/**
 * 将proTable的sort转成字符串：field
 * @param sort
 */
export function getOrderStr(sort: Record<string, SortOrder> | undefined): string {
  if (!sort) {
    return '';
  }
  const renArray: string[] = [];
  Object.keys(sort).forEach((key) => {
    renArray.push(`${key} ${getASC(sort[key])}`);
  });

  return renArray.toString();
}

export function getWheres(params: Record<string, any>, newName: Record<string, string>) {
  // 先过滤出不必要项目
  const moitParams = omit(params, ['current', 'pageSize', 'keyword']);

  // 变更名称
  const newParams: Record<string, any> = {};
  Object.keys(moitParams).forEach((key) => {
    if (moitParams[key] !== '') {
      const newKey = newName[key] ? newName[key] : key;
      newParams[newKey] = moitParams[key];
    }
  });
  return newParams;
}

// JS 正则去除 textarea 产生的空行，并用,进行分割
export function replaceTextArea(text: string) {
  if (!text) {
    return '';
  }
  const reg = /\n(\n)*( )*(\n)*\n/g;
  let ren = text.replace(reg, '\n');
  ren = ren.replace(/[\r\n]/g, ',').replace(/[\n]/g, ',');
  if (ren.lastIndexOf(',') === ren.length - 1) {
    ren = ren.substr(0, ren.length - 1);
  }
  return ren;
}

/**
 * 在编辑表格中得到一个新的ID
 */
export const getNewId = (): number => {
  const radom = (Math.random() * 1000000).toFixed(0);
  return Number(radom);
};

export const getNegativeNewId = (): number => {
  return -getNewId();
};

/**
 * 由于编辑框中，antDesign会自动添加一些数据，例如index。
 * 另外还有一些从数据库得到的一些临时数据，所以要剔除一部分数据
 * @param originalData 原始的数据
 * @param filterKeys 要去掉的内容
 */
export const omitEditTableData = (
  originalData: Record<string, any>[],
  filterKeys: string[],
): Record<string, any> => {
  // 定义要返回的内容
  const ren: Record<string, any>[] = [];
  for (let i = 0; i < originalData.length; i += 1) {
    ren.push(omit(originalData[i], filterKeys));
  }
  return ren;
};

// ---------------------------------------------------------------------------------

type timeZoneItem = {
  label: string;
  value: number;
  text: string;
};
const timeZoneArray: timeZoneItem[] = [
  { label: '(GMT -12:00) Eniwetok, Kwajalein', value: -12, text: 'Pacific/Kwajalein' },
  { label: '(GMT -11:00) Midway Island, Samoa', value: -11, text: 'Pacific/Samoa' },
  { label: '(GMT -10:00) Hawaii', value: -10, text: 'US/Hawaii' },
  { label: '(GMT -9:00) Alaska', value: -9, text: 'US/Alaska' },
  { label: '(GMT -8:00) Pacific Time (US + Canada)', value: -8, text: 'America/Tijuana' },
  { label: '(GMT -7:00) Mountain Time (US + Canada)', value: -7, text: 'US/Arizona' },
  {
    label: '(GMT -6:00) Central Time (US + Canada), Mexico City',
    value: -6,
    text: 'America/Mexico_City',
  },
  {
    label: '(GMT -5:00) Eastern Time (US + Canada), Bogota, Lima',
    value: -5,
    text: 'America/Bogota',
  },
  {
    label: '(GMT -4:00) Atlantic Time (Canada), Caracas, La Paz',
    value: -4,
    text: 'America/Caracas',
  },
  { label: '(GMT -3:30) Newfoundland', value: -3.5, text: 'Canada/Newfoundland' },
  {
    label: '(GMT -3:00) Brazil, Buenos Aires, Georgetown',
    value: -3,
    text: 'America/Buenos_Aires',
  },
  { label: '(GMT -2:00) Mid-Atlantic', value: -2, text: 'Atlantic/St_Helena' },
  { label: '(GMT -1:00) Azores, Cape Verde Islands', value: -1, text: 'Atlantic/Azores' },
  {
    label: '(GMT -0:00) London, Western Europe, Lisbon, Casablanca',
    value: 0,
    text: 'Europe/Dublin',
  },
  { label: '(GMT +1:00) Brussels, Copenhagen, Madrid, Paris', value: 1, text: 'Europe/Amsterdam' },
  { label: '(GMT +2:00) Kaliningrad, South Africa', value: 2, text: 'Africa/Cairo' },
  { label: '(GMT +3:00) Baghdad, Riyadh, Moscow, St. Petersburg', value: 3, text: 'Asia/Baghdad' },
  { label: '(GMT +3:30) Tehran', value: 3.5, text: 'Asia/Tehran' },
  { label: '(GMT +4:00) Abu Dhabi, Muscat, Baku, Tbilisi', value: 4, text: 'Asia/Baku' },
  { label: '(GMT +4:30) Kabul', value: 4.5, text: 'Asia/Kabul' },
  {
    label: '(GMT +5:00) Ekaterinburg, Islamabad, Karachi, Tashkent',
    value: 5,
    text: 'Asia/Karachi',
  },
  { label: '(GMT +5:30) Bombay, Calcutta, Madras, New Delhi', value: 5.5, text: 'Asia/Calcutta' },
  { label: '(GMT +5:45) Kathmandu', value: 5.75, text: 'Asia/Katmandu' },
  { label: '(GMT +6:00) Almaty, Dhaka, Colombo', value: 6, text: 'Asia/Almaty' },
  { label: '(GMT +7:00) Bangkok, Hanoi, Jakarta', value: 7, text: 'Asia/Bangkok' },
  { label: '(GMT +8:00) Beijing, Perth, Singapore, Hong Kong', value: 8, text: 'Asia/Shanghai' },
  { label: '(GMT +9:00) Tokyo, Seoul, Osaka, Sapporo, Yakutsk', value: 9, text: 'Asia/Tokyo' },
  { label: '(GMT +9:30) Adelaide, Darwin', value: 9.5, text: 'Australia/Adelaide' },
  {
    label: '(GMT +10:00) Eastern Australia, Guam, Vladivostok',
    value: 10,
    text: 'Australia/Canberra',
  },
  {
    label: '(GMT +11:00) Magadan, Solomon Islands, New Caledonia',
    value: 11,
    text: 'Asia/Magadan',
  },
  {
    label: '(GMT +12:00) Auckland, Wellington, Fiji, Kamchatka',
    value: 12,
    text: 'Pacific/Auckland',
  },
];

export const getTimeZoneOption = () => {
  const ren = timeZoneArray.map((item) => {
    return { label: item.label, value: item.text };
  });
  return ren;
};

/**
 * 返回文件大小K M G T
 * @param fileByte 文件的大小
 * @returns
 */
export function getFileSize(fileByte: number) {
  const fileSizeByte = fileByte;
  let fileSizeMsg = '';
  if (fileSizeByte < 1048576) fileSizeMsg = `${Math.round(fileSizeByte / 1024)}K`;
  else if (fileSizeByte === 1048576) fileSizeMsg = '1M';
  else if (fileSizeByte > 1048576 && fileSizeByte < 1073741824)
    fileSizeMsg = `${(fileSizeByte / (1024 * 1024)).toFixed(2)}M`;
  else if (fileSizeByte > 1048576 && fileSizeByte === 1073741824) fileSizeMsg = '1G';
  else if (fileSizeByte > 1073741824 && fileSizeByte < 1099511627776)
    fileSizeMsg = `${fileSizeByte / (1024 * 1024 * 1024)}G`;
  else fileSizeMsg = '文件超过1T';
  return fileSizeMsg;
}

// ---------------------得到一个时间的区间------------------------------------
type RangePickerValue = RangePickerProps<moment.Moment>['value'];

export function fixedZero(val: number) {
  return val * 1 < 10 ? `0${val}` : val;
}

// 按照类型得到不同时间的区间
export function getTimeDistance(type: 'today' | 'week' | 'month' | 'year'): RangePickerValue {
  const now = new Date();
  const oneDay = 1000 * 60 * 60 * 24;

  if (type === 'today') {
    now.setHours(0);
    now.setMinutes(0);
    now.setSeconds(0);
    return [moment(now), moment(now.getTime() + (oneDay - 1000))];
  }

  if (type === 'week') {
    let day = now.getDay();
    now.setHours(0);
    now.setMinutes(0);
    now.setSeconds(0);

    if (day === 0) {
      day = 6;
    } else {
      day -= 1;
    }

    const beginTime = now.getTime() - day * oneDay;

    return [moment(beginTime), moment(beginTime + (7 * oneDay - 1000))];
  }
  const year = now.getFullYear();

  if (type === 'month') {
    const month = now.getMonth();
    const nextDate = moment(now).add(1, 'months');
    const nextYear = nextDate.year();
    const nextMonth = nextDate.month();

    return [
      moment(`${year}-${fixedZero(month + 1)}-01 00:00:00`),
      moment(moment(`${nextYear}-${fixedZero(nextMonth + 1)}-01 00:00:00`).valueOf() - 1000),
    ];
  }

  return [moment(`${year}-01-01 00:00:00`), moment(`${year}-12-31 23:59:59`)];
}
